/*
 * COPYRIGHT. ShenZhen JiMi Technology Co., Ltd. 2017.
 * ALL RIGHTS RESERVED.
 *
 * No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
 * on any form or by any means, electronic, mechanical, photocopying, recording, 
 * or otherwise, without the prior written permission of ShenZhen JiMi Network Technology Co., Ltd.
 *
 * Amendment History:
 * 
 * Date                   By              Description
 * -------------------    -----------     -------------------------------------------
 * 2017年4月11日    li.shangzhi         Create the class
 * http://www.jimilab.com/
 */

package com.jimi.web.api.impl;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.jimi.app.dto.output.ApiAppInfoOutputDto;
import com.jimi.app.model.ApiAppFunsEntity;
import com.jimi.app.model.ApiAppInfoEntity;
import com.jimi.app.model.ApiOpenFunctionsEntity;
import com.jimi.app.service.IApiAppFunsService;
import com.jimi.app.service.IApiAppInfoService;
import com.jimi.app.service.IApiOpenFunctionsService;
import com.jimi.commons.DatetimeUtil;
import com.jimi.exception.SysApiException;
import com.jimi.framework.annotation.filter.ReqFilter;
import com.jimi.framework.annotation.log.LoggerProfile;
import com.jimi.framework.base.BaseApi;
import com.jimi.framework.bean.BeanUtil;
import com.jimi.framework.cache.redis.RedisUtil;
import com.jimi.framework.cache.redis.RedisUtil.ModuleType;
import com.jimi.framework.utils.DESEncrypt;
import com.jimi.framework.utils.MD5Utils;
import com.jimi.framework.utils.UUIDGenerator;
import com.jimi.web.api.IOAuthApiService;
import com.jimi.web.dto.output.AccessTokenOutputDto;
import com.jimi.web.model.CoreUser;
import com.jimi.web.service.IUserService;

/**
 * @FileName OAuthApiServiceImpl.java
 * @Description:
 *
 * @Date 2017年4月11日 上午11:41:37
 * @author li.shangzhi
 * @version 1.0
 */
@Service
public class OAuthApiServiceImpl extends BaseApi implements IOAuthApiService {

	@Resource
	private IApiAppInfoService appInfoService;

	@Resource
	private IApiOpenFunctionsService apiOpenFunctionsService;

	@Resource
	private IApiAppFunsService apiAppFunsService;

	@Resource
	private IUserService userService;

	@Override
	@LoggerProfile(methodNote = "IOAuthApiService.getAppkeyAndSecret")
	public ApiAppInfoOutputDto getAppkeyAndSecret(String account, String userPwd, String projectCode, String appDesc) {
		CoreUser coreUserEntity = userService.getUserInfo(account);
		if (null == coreUserEntity) {
			return null;
		}
		if (!userPwd.equals(coreUserEntity.getPassword())) {
			return null;
		}
		int userId = coreUserEntity.getId();
		String appKey = DESEncrypt.encrypt(projectCode + "," + coreUserEntity.getId());
		ApiAppInfoEntity apiAppInfoEntity = appInfoService.getById(String.valueOf(userId));
		if (null == apiAppInfoEntity) {
			apiAppInfoEntity = new ApiAppInfoEntity();
			apiAppInfoEntity.setUserId(userId);
			apiAppInfoEntity.setAccount(account);
			apiAppInfoEntity.setProjectCode(projectCode);
			apiAppInfoEntity.setAppKey(appKey);
			apiAppInfoEntity.setAppSecret(UUIDGenerator.get32LowCaseUUID());
			apiAppInfoEntity.setAppDesc(appDesc);
			apiAppInfoEntity.setCreateTime(new Date());
			apiAppInfoEntity.setEnabled(true);
			appInfoService.insert(apiAppInfoEntity);
		}

		// 给分配的appkey生成所有接口数据
		ApiOpenFunctionsEntity apiOpenFunctionsEntity = new ApiOpenFunctionsEntity();
		apiOpenFunctionsEntity.setRouteId("open.aichezaixian.com");
		List<ApiOpenFunctionsEntity> openFunsList = apiOpenFunctionsService.findList(apiOpenFunctionsEntity);
		for (ApiOpenFunctionsEntity openFunEntity : openFunsList) {
			ApiAppFunsEntity apiAppFunsEntity = new ApiAppFunsEntity();
			apiAppFunsEntity.setAppKey(appKey);
			apiAppFunsEntity.setFunId(openFunEntity.getId());
			apiAppFunsEntity.setFunName(openFunEntity.getMethodDesc());
			apiAppFunsEntity.setReqPerSecond(100); // 默认每秒100次
			apiAppFunsEntity.setReqPerDay(1440); // 默认每天1440次
			apiAppFunsService.insert(apiAppFunsEntity);
		}

		return (ApiAppInfoOutputDto) BeanUtil.convertBean(apiAppInfoEntity, ApiAppInfoOutputDto.class);
	}

	@Override
	@ReqFilter(keySpel = "'getToken_'+#appKey+'_'+#account", limit = 1, time = 60000)
	@LoggerProfile(methodNote = "IOAuthApiService.createAccessToken")
	public AccessTokenOutputDto createAccessToken(String appKey, String userId, String account, Integer expiresIn) throws SysApiException {
		String redisKey = appKey +"_"+ userId +"_"+ account;
		String tokenObj = RedisUtil.getString(ModuleType.OAUTH, redisKey);
		if(StringUtils.isNotBlank(tokenObj)) {
			logger.info("token还未过期，appKey：" + appKey + "，userId：" + userId + "，expiresIn：" + expiresIn + "，tokenObj：" + tokenObj);
			return JSONObject.parseObject(tokenObj, AccessTokenOutputDto.class);
		}
		// accessToken生成规则，总账号的appKey+申请的userId+expiresIn+时间戳
		String accessToken = MD5Utils.getMD5ofStr(appKey + userId + expiresIn + System.currentTimeMillis());
		// refreshToken生成规则，总账号的appKey+申请的account+expiresIn+时间戳
		String refreshToken = MD5Utils.getMD5ofStr(appKey + account + expiresIn + System.currentTimeMillis());

		AccessTokenOutputDto accessTokenOutputDto = new AccessTokenOutputDto();
		accessTokenOutputDto.setAppKey(appKey);
		accessTokenOutputDto.setUserId(userId);
		accessTokenOutputDto.setAccount(account);
		accessTokenOutputDto.setAccessToken(accessToken);
		accessTokenOutputDto.setRefreshToken(refreshToken);
		accessTokenOutputDto.setExpiresIn(expiresIn);
		accessTokenOutputDto.setTime(DatetimeUtil.getCurrentDate());
		RedisUtil.set(ModuleType.OAUTH, accessToken, JSONObject.toJSONString(accessTokenOutputDto), expiresIn, TimeUnit.SECONDS);
		RedisUtil.set(ModuleType.OAUTH, redisKey, JSONObject.toJSONString(accessTokenOutputDto), expiresIn, TimeUnit.SECONDS);
		return accessTokenOutputDto;
	}

	@Override
	@ReqFilter(keySpel = "'refreshToken_'+#accessToken+'_'+#refreshToken", limit = 1, time = 60000)
	@LoggerProfile(methodNote = "IOAuthApiService.refreshAccessToken")
	public AccessTokenOutputDto refreshAccessToken(String accessToken, String refreshToken, Integer expiresIn) throws SysApiException {
		String tokenObj = RedisUtil.getString(ModuleType.OAUTH, accessToken);
		if(StringUtils.isNotBlank(tokenObj)) {
			AccessTokenOutputDto accessTokenOutputDto = JSONObject.parseObject(tokenObj, AccessTokenOutputDto.class);
			String rToken = accessTokenOutputDto.getRefreshToken();
			if(rToken.equals(refreshToken)) {
				String appKey = accessTokenOutputDto.getAppKey();
				String userId = accessTokenOutputDto.getUserId();
				String account = accessTokenOutputDto.getAccount();
				
				String redisKey = appKey +"_"+ userId +"_"+ account;
				// accessToken生成规则，总账号的appKey+申请的userId+expiresIn+时间戳
				String aToken = MD5Utils.getMD5ofStr(appKey + userId + expiresIn + System.currentTimeMillis());
				// refreshToken生成规则，总账号的appKey+申请的account+expiresIn+时间戳
				rToken = MD5Utils.getMD5ofStr(appKey + account + expiresIn + System.currentTimeMillis());
				
				accessTokenOutputDto.setAppKey(appKey);
				accessTokenOutputDto.setUserId(userId);
				accessTokenOutputDto.setAccount(account);
				accessTokenOutputDto.setAccessToken(aToken);
				accessTokenOutputDto.setRefreshToken(rToken);
				accessTokenOutputDto.setExpiresIn(expiresIn);
				accessTokenOutputDto.setTime(DatetimeUtil.getCurrentDate());
				
				// 删除原有的key
				RedisUtil.delete(ModuleType.OAUTH, accessToken);
				RedisUtil.delete(ModuleType.OAUTH, refreshToken);
				
				String jsonStr = JSONObject.toJSONString(accessTokenOutputDto);
				// 续命
				RedisUtil.set(ModuleType.OAUTH, redisKey, jsonStr, expiresIn, TimeUnit.SECONDS);
				// 新增新的key
				RedisUtil.set(ModuleType.OAUTH, aToken, jsonStr, expiresIn, TimeUnit.SECONDS);
				RedisUtil.set(ModuleType.OAUTH, rToken, jsonStr, expiresIn, TimeUnit.SECONDS);
				
				return accessTokenOutputDto;
			} else {
				logger.info("refreshToken值：{}不存在", refreshToken);
			}
			return null;
		} else {
			logger.info("accessToken值：{}不存在", accessToken);
		}
		return null;
	}
}
